package session.stateful;

import entity.CapacityControlEntity;
import entity.CustomerEntity;
import entity.FnBBranchEntity;
import entity.FnBProductEntity;
import entity.FnBReservationEntity;
import entity.MealEntity;
import entity.ReservationEntity;
import entity.ReservedMealEntity;
import entity.ReservedSetMealEntity;
import entity.ReservedTableEntity;
import entity.SetMealEntity;
import entity.TableTypeEntity;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.ejb.Stateless;
import javax.ejb.LocalBean;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

@Stateless
@LocalBean
public class ReservationSessionBean {

    @PersistenceContext
    EntityManager entityManager;
    private FnBReservationEntity fandBReservation;

    public String addReservation(FnBReservationEntity reservation, Long customerId, long branchId, List<List<FnBProductEntity>> choiceList, Map<Long, Double> priceList, Map<Long, Integer> quantityList, List<TableTypeEntity> selectedTable, List<Integer> selectedTableQuantity) {
        CustomerEntity customer = entityManager.find(CustomerEntity.class, customerId);
        FnBBranchEntity branch = entityManager.find(FnBBranchEntity.class, branchId);
        entityManager.persist(reservation);
        branch.getReservation().add(reservation);
        reservation.setBranch(branch);
        double deposit = 0;

        for (int i = 0; i < choiceList.size() - 1; i++) {
            for (FnBProductEntity p : choiceList.get(i)) {
                MealEntity meal = (MealEntity) p;
                int quantity = quantityList.get(meal.getId());
                double onlinePrice = priceList.get(meal.getId());
                deposit += onlinePrice * quantity * meal.getDeposit() /100;
                ReservedMealEntity resMeal = new ReservedMealEntity();
                resMeal.setPrice(onlinePrice);
                resMeal.setQuantity(quantity);
                resMeal.setDeposit(onlinePrice * quantity * meal.getDeposit()/100);
                resMeal.setShowCharge(onlinePrice * quantity * meal.getShowCharge()/100);
                resMeal.setNoShowCharge(onlinePrice * quantity * meal.getNoShowCharge()/100);
                resMeal.setPointReceived(onlinePrice * quantity * meal.getPointReceived()/100);
                entityManager.persist(resMeal);

                resMeal.setFandBReservation(reservation);
                reservation.getReservedMeal().add(resMeal);

                resMeal.setMeal(meal);
                meal.getReservedMeal().add(resMeal);
                entityManager.merge(meal);
            }
        }

        for (FnBProductEntity p : choiceList.get(choiceList.size() - 1)) {
            SetMealEntity set = (SetMealEntity) p;
            int quantity = quantityList.get(set.getId());
            double onlinePrice = priceList.get(set.getId());
            deposit += onlinePrice * quantity * set.getDeposit()/100;
            ReservedSetMealEntity resMeal = new ReservedSetMealEntity();
            resMeal.setPrice(onlinePrice);
            resMeal.setQuantity(quantity);
            resMeal.setDeposit(onlinePrice * quantity * set.getDeposit()/100);
            resMeal.setShowCharge(onlinePrice * quantity * set.getShowCharge()/100);
            resMeal.setNoShowCharge(onlinePrice * quantity * set.getNoShowCharge()/100);
            resMeal.setPointReceived(onlinePrice * quantity * set.getPointReceived()/100);
            entityManager.persist(resMeal);

            resMeal.setFandBReservation(reservation);
            reservation.getReservedSetMeal().add(resMeal);

            resMeal.setSetMeal(set);
            set.getReservedSetMeal().add(resMeal);
            entityManager.merge(set);
        }



        reservation.setDeposit(deposit);

        for (int i = 0; i < selectedTable.size(); i++) {
            TableTypeEntity table = selectedTable.get(i);
            ReservedTableEntity reservedTable = new ReservedTableEntity();
            reservedTable.setQuantity(selectedTableQuantity.get(i));
            reservedTable.setTableType(table);
            reservedTable.setFandBReservation(reservation);
            entityManager.persist(reservedTable);
            table.getReservedTable().add(reservedTable);
            entityManager.merge(table);
            reservation.getReservedTable().add(reservedTable);
        }
        customer.getReservation().add(reservation);
        entityManager.merge(customer);
        reservation.setCustomer(customer);

        entityManager.flush();
        if (!branch.getFnBIOTR().isAutoConfirm() && checkOverload(branch, reservation)) {
            reservation.setConfirmation("Not confirmed");
            return "Please wait for the restaurant to confirm the reservation";
        }
        reservation.setConfirmation("Confirmed");
        reservation.setCustomerStatus("Pending");
        return "Your reservation has been confirmed";
    }

    private boolean checkOverload(FnBBranchEntity branch, FnBReservationEntity reservation) {
        List<ReservedTableEntity> list = reservation.getReservedTable();
        double percent = branch.getFnBIOTR().getPercentManualConfirm();
        for (ReservedTableEntity temp : list) {
            TableTypeEntity table = temp.getTableType();
            int[][] used = getUsed(table, reservation.getDateReserved());
            int maximum = getMaximum(table, reservation.getDateReserved());
            for (int i = 0; i < 24; i++) {
                for (int j = 0; j < 4; j++) {
                    if ((used[i][j] * 1.0 / maximum) * 100 > percent) {
                        return true;
                    }
                }
            }

        }
        System.out.println("NO OVERLOAD!");
        return false;
    }

    public List<TableTypeEntity> getTableList(long branchId) {
        FnBBranchEntity branch = entityManager.find(FnBBranchEntity.class, branchId);
        return branch.getTableType();
    }

    public int[][] getAvailTable(long tableId, Date dateReserved) {
        TableTypeEntity table = entityManager.find(TableTypeEntity.class, tableId);

        int maximum = getMaximum(table, dateReserved);
        int[][] used = getUsed(table, dateReserved);

        for (int i = 0; i < used.length; i++) {
            for (int j = 0; j < used[i].length; j++) {
                used[i][j] = maximum - used[i][j];
            }
        }

        return used;
    }

    private int getMaximum(TableTypeEntity table, Date dateReserved) {
        List<CapacityControlEntity> capacityList = table.getCapacityControl();

        int normal = -1;
        int dayOfWeek = - 1;
        int specific = -1;
        int date = dateReserved.getDay() + 1;

        for (CapacityControlEntity c : capacityList) {
            if (c.getType() == 8) {
                Date tempDate = c.getSpecificDate();
                if (compareDate(tempDate, dateReserved)) {
                    specific = c.getNumberOfTable();
                }
            } else if (date == c.getType()) {
                dayOfWeek = c.getNumberOfTable();
            } else {
                normal = c.getNumberOfTable();
            }
        }

        if (specific != - 1) {
            return specific;
        }

        if (dayOfWeek != - 1) {
            return dayOfWeek;
        }

        return normal;
    }

    private int[][] getUsed(TableTypeEntity table, Date dateReserved) {
        List<ReservedTableEntity> fullList = table.getReservedTable();

        int[][] time = new int[24][4];

        for (ReservedTableEntity t : fullList) {
            FnBReservationEntity r = t.getFandBReservation();
            if ((compareDate(r.getDateReserved(), dateReserved))) {
                int beginHour = r.getTimeBegin().getHours();
                int beginMinute = r.getTimeBegin().getMinutes();

                int endHour = r.getTimeEnd().getHours();
                int endMinute = r.getTimeEnd().getMinutes();

                while (beginHour != endHour || beginMinute != endMinute) {
                    time[beginHour][beginMinute / 15] += t.getQuantity();

                    beginHour += (beginMinute + 15) / 60;
                    beginMinute = (beginMinute + 15) % 60;
                    beginHour = beginHour % 24;
                }
            }
        }
        return time;
    }

    private boolean compareDate(Date d1, Date d2) {
        return d1.getDate() == d2.getDate() && d1.getMonth() == d2.getMonth() && d1.getYear() == d2.getYear();
    }

    public int getIntervalByBranchId(long branchId) {
        FnBBranchEntity branch = entityManager.find(FnBBranchEntity.class, branchId);

        double eatingTime = branch.getFnBIOTR().getEatingTime();
        return getInterval(eatingTime);
    }

    private int getInterval(double eatingTime) {
        int hour = (int) eatingTime;
        int minute = 0;
        double minuteEat = (eatingTime - hour) * 100;

        if (minuteEat <= 0) {
            minute = 0;
        } else if (minuteEat <= 25) {
            minute = 1;
        } else if (minuteEat <= 50) {
            minute = 2;
        } else if (minuteEat <= 75) {
            minute = 3;
        }

        return hour * 4 + minute;
    }

    public List<ReservationEntity> getReservationListByBranchId(long id) {
        FnBBranchEntity branch = entityManager.find(FnBBranchEntity.class, id);
        return branch.getReservation();
    }
     public void toShow(Long id) {
        fandBReservation = entityManager.find(FnBReservationEntity.class, id);
        fandBReservation.setCustomerStatus("Show");
        entityManager.merge(fandBReservation);
        entityManager.flush();
    }

    public void toNoShow(Long id) {
        fandBReservation = entityManager.find(FnBReservationEntity.class, id);
        fandBReservation.setCustomerStatus("No Show");
        entityManager.merge(fandBReservation);
        entityManager.flush();
    }

    public void toConfirmed(Long id) {
        fandBReservation = entityManager.find(FnBReservationEntity.class, id);
        fandBReservation.setConfirmation("Confirmed");
        entityManager.merge(fandBReservation);
        entityManager.flush();
    }

    public void toRejected(Long id) {
        fandBReservation = entityManager.find(FnBReservationEntity.class, id);
        fandBReservation.setConfirmation("Rejected");
        if (fandBReservation.getReservedMeal().size()>0){
        fandBReservation.setReservedMeal(null);
        //delete ReservedMeal        
        }
        if (fandBReservation.getReservedSetMeal().size()>0){
        fandBReservation.setReservedSetMeal(null);
        //delete ReserveSetMeal
        }
        if (fandBReservation.getReservedTable().size()>0){
        fandBReservation.setReservedTable(null);
        //delete ReservedTable
        }
        
        entityManager.merge(fandBReservation);
        entityManager.flush();
    }
}
